package sample.plugin.http.lang.decision;

import android.util.ArrayMap;

import com.rapid.api.lang.engine.highlight.decision.DecisionResult;
import com.rapid.api.lang.engine.highlight.token.IdentifierToken;
import com.rapid.api.lang.engine.highlight.token.TokenModel;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import io.github.rosemoe.sora.widget.schemes.EditorColorScheme;
import sample.plugin.http.entity.RequestEntity;
import sample.plugin.http.window.RequestWindowEvent;

public class RequestDecision extends AbstractDecision {
    private final static String KIND_POST = "post";
    private final static String KIND_GET = "get";
    private final static String KIND_PUT = "put";
    private final static String KIND_DELETE = "delete";
    private final static String KEY_HEADER = "header";
    private final static String KEY_PARAM = "param";

    private final Map<Integer, RequestEntity> requests = new ArrayMap<>();

    @Override
    public Iterable<DecisionResult> decide(TokenModel model, State state) {
        if (model.line == state.requestLine) {
            return singleColorBold(EditorColorScheme.KEYWORD);
        }
        List<DecisionResult> results = new ArrayList<>();
        switch (model.token) {
            case IdentifierToken.COLON:
            case IdentifierToken.LBRACE:
            case IdentifierToken.RBRACE: {
                DecisionResult result1 = new DecisionResult(
                        DecisionResult.ResultKind.ACCEPT,
                        new DecisionResult.StyleContent(EditorColorScheme.OPERATOR)
                );
                results.add(result1);
                if (model.line == state.urlLine) {
                    DecisionResult result2 = new DecisionResult(
                            DecisionResult.ResultKind.ACCEPT,
                            new DecisionResult.StyleContent(EditorColorScheme.STRING, false, true)
                    );
                    results.add(result2);
                }
                break;
            }
            case IdentifierToken.LPAREN:
            case IdentifierToken.RPAREN: {
                DecisionResult result = new DecisionResult(
                        DecisionResult.ResultKind.ACCEPT,
                        new DecisionResult.StyleContent(EditorColorScheme.OPERATOR)
                );
                results.add(result);
                break;
            }
            case IdentifierToken.IDENTIFIER: {
                TokenModel next = getNextNonEmptyToken(model);
                if (next == null) {
                    return refuse();
                }
                switch (model.text) {
                    case KIND_POST:
                    case KIND_GET:
                    case KIND_PUT:
                    case KIND_DELETE:
                        if (next.token == IdentifierToken.LPAREN) {
                            state.urlLine = model.line;
                            DecisionResult result = new DecisionResult(
                                    DecisionResult.ResultKind.ACCEPT,
                                    new DecisionResult.StyleContent(EditorColorScheme.CLASS)
                            );
                            results.add(result);
                        } else if (model.line == state.urlLine) {
                            DecisionResult result2 = new DecisionResult(
                                    DecisionResult.ResultKind.ACCEPT,
                                    new DecisionResult.StyleContent(EditorColorScheme.STRING, false, true)
                            );
                            results.add(result2);
                        }
                        break;
                    case KEY_HEADER:
                    case KEY_PARAM:
                        if (next.token == IdentifierToken.COLON) {
                            DecisionResult result = new DecisionResult(
                                    DecisionResult.ResultKind.ACCEPT,
                                    new DecisionResult.StyleContent(EditorColorScheme.FUNCTION)
                            );
                            results.add(result);
                        } else if (model.line == state.urlLine) {
                            DecisionResult result2 = new DecisionResult(
                                    DecisionResult.ResultKind.ACCEPT,
                                    new DecisionResult.StyleContent(EditorColorScheme.STRING, false, true)
                            );
                            results.add(result2);
                        }
                        break;
                    default:
                        if (model.line == state.urlLine) {
                            DecisionResult result2 = new DecisionResult(
                                    DecisionResult.ResultKind.ACCEPT,
                                    new DecisionResult.StyleContent(EditorColorScheme.STRING, false, true)
                            );
                            results.add(result2);
                        }
                        break;
                }
                return results;
            }
            case IdentifierToken.SHARP: {
                if (model.prev == null || getPrevNonEmptyToken(model).token == IdentifierToken.NEWLINE) {
                    state.requestLine = model.line;
                    RequestEntity requestEntity = parseRequestEntity(model);
                    requests.put(model.line, requestEntity);

                    DecisionResult result = new DecisionResult();
                    result.kind = DecisionResult.ResultKind.ICON;
                    result.content = new DecisionResult.IconContent(RequestWindowEvent.runDrawable);
                    results.add(result);

                    DecisionResult color = new DecisionResult(
                            DecisionResult.ResultKind.ACCEPT,
                            new DecisionResult.StyleContent(EditorColorScheme.KEYWORD, true, false)
                    );
                    results.add(color);
                } else if (model.line == state.urlLine) {
                    DecisionResult result2 = new DecisionResult(
                            DecisionResult.ResultKind.ACCEPT,
                            new DecisionResult.StyleContent(EditorColorScheme.STRING, false, true)
                    );
                    results.add(result2);
                }
                break;
            }
            default:
                if (model.line == state.urlLine) {
                    DecisionResult result = new DecisionResult(
                            DecisionResult.ResultKind.ACCEPT,
                            new DecisionResult.StyleContent(EditorColorScheme.STRING, false, true)
                    );
                    results.add(result);
                }
                break;
        }
        return results;
    }

    private TokenModel model;

    private RequestEntity parseRequestEntity(TokenModel model) {
        this.model = model;
        RequestEntity entity = new RequestEntity();
        //解析请求名称
        parseRequestName(entity);
        //解析请求方式和请求地址
        parseRequestType(entity);
        parseRequestUrl(entity);
        //解析header或param
        parseRequestData(entity);
        return entity;
    }

    private void parseRequestName(RequestEntity entity) {
        skip(IdentifierToken.SHARP);
        model = getNextNonEmptyToken(model);
        String requestName = "";
        while (model != null) {
            if (model.token == IdentifierToken.NEWLINE) {
                model = model.next;
                break;
            }
            requestName += model.text;
            model = model.next;
        }
        entity.name = requestName.trim();
    }

    private void parseRequestType(RequestEntity entity) {
        while (model != null) {
            if (model.token == IdentifierToken.IDENTIFIER) {
                String type = model.text;
                switch (type) {
                    case KIND_POST:
                        entity.kind = RequestEntity.Kind.POST;
                        break;
                    case KIND_GET:
                        entity.kind = RequestEntity.Kind.GET;
                        break;
                    case KIND_PUT:
                        entity.kind = RequestEntity.Kind.PUT;
                        break;
                    case KIND_DELETE:
                        entity.kind = RequestEntity.Kind.DELETE;
                        break;
                }
                break;
            }
            model = model.next;
        }
    }

    private void parseRequestUrl(RequestEntity entity) {
        skip(IdentifierToken.LPAREN);
        String url = "";
        while (model != null) {
            if (model.token == IdentifierToken.RPAREN) {
                model = model.next;
                break;
            }
            url += model.text;
            model = model.next;
        }
        entity.url = url;
    }

    private void parseRequestData(RequestEntity entity) {
        while (model != null) {
            if (model.token == IdentifierToken.NEWLINE || model.token == IdentifierToken.WHITESPACE) {
                model = model.next;
                continue;
            } else if (model.token == IdentifierToken.SHARP || model.token == IdentifierToken.EOF) {
                break;
            } else if (model.token == IdentifierToken.IDENTIFIER) {
                if (KEY_HEADER.equals(model.text)) {
                    parseRequestHeaders(entity);
                } else if (KEY_PARAM.equals(model.text)) {
                    parseRequestParam(entity);
                }
            }
            model = model.next;
        }
    }

    private void parseRequestHeaders(RequestEntity entity) {
        skip(IdentifierToken.LBRACE);
        skip(IdentifierToken.NEWLINE);
        while (model != null && model.token != IdentifierToken.RBRACE) {
            parseRequestHeader(entity);
        }
    }

    private void parseRequestHeader(RequestEntity entity) {
        model = getNextNonEmptyToken(model);
        if (model.token == IdentifierToken.NEWLINE || model.token == IdentifierToken.RBRACE) {
            return;
        }
        String headerName = "";
        while (model != null) {
            if (model.token == IdentifierToken.COLON) {
                model = model.next;
                break;
            }
            headerName += model.text;
            model = model.next;
        }
        model = getNextNonEmptyToken(model);
        String headerValue = "";
        while (model != null) {
            if (model.token == IdentifierToken.NEWLINE) {
                model = model.next;
                break;
            }
            headerValue += model.text;
            model = model.next;
        }
        if (entity.headers == null) {
            entity.headers = new ArrayMap<>();
        }
        entity.headers.put(headerName, headerValue);
    }

    private void parseRequestParam(RequestEntity entity) {
        skip(IdentifierToken.COLON);
        model = getNextNonEmptyToken(model);
        if (model == null) {
            return;
        }
        String param = "";
        if (model.token == IdentifierToken.LBRACE) {
            while (model != null) {
                if (model.token == IdentifierToken.RBRACE) {
                    model = model.next;
                    break;
                }
                param += model.text;
                model = model.next;
            }
        } else {
            while (model != null) {
                if (model.token == IdentifierToken.NEWLINE) {
                    break;
                }
                param += model.text;
                model = model.next;
            }
        }
        entity.param = param;
    }

    private void skip(int token) {
        while (model != null) {
            if (model.token == token) {
                model = model.next;
                break;
            }
            model = model.next;
        }
    }

    public RequestEntity getRequestModel(int line) {
        return requests.get(line);
    }

    public void clear() {
        requests.clear();
    }
}
